package com.killer.catalina;

import com.killer.loader.WebAppClassLoader;
import com.killer.servlet.Servlet;
import com.killer.servlet.ServletRequest;
import com.killer.servlet.ServletResponse;
import com.killer.util.HttpProtocolUtil;
import com.killer.util.ThreadPoolUtil;
import com.killer.view.Request;
import com.killer.view.Response;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;

/**
 * 对应server.xml配置文件的Connector标签
 */
public class Connector implements Lifecycle{

    /**
     * 这里保存一个对上层Service的引用，方便匹配
     */
    private Service service;

    /**
     * 监听的端口号
     */
    private int port;

    public Service getService() {
        return service;
    }

    public void setService(Service service) {
        this.service = service;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    @Override
    public void start() {
        try {
            ServerSocket serverSocket = new ServerSocket(port);
            System.out.println("MiniCat start");
            while (true) {
                Socket socket = serverSocket.accept();
                ThreadPoolUtil.execute(new Pooler(socket));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public class Pooler implements Runnable{

        private Socket socket;

        public Pooler(Socket socket) {
            this.socket=socket;
        }

        @Override
        public void run() {
            try {
                InputStream inputStream=socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream();
                Request request = new Request(inputStream);
                Response response= new Response(outputStream);
                if (StringUtils.isBlank(request.getHost())) {
                    return;
                }
                //要将其封装成ServletRequest和Servlet对象，用于与Servlet容器交互
                service(request, response);
                inputStream.close();
                outputStream.flush();
                outputStream.close();
                socket.close();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

        }

        public void service(Request request,Response response) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
            //获取当前service
            StandardService service=(StandardService)getService();
            //获取engine
            StandardEngine engine = (StandardEngine) service.getEngine();
            //获取host
            StandardHost host = engine.mapperHost(request, response);
            if (host == null) {
                response.response(HttpProtocolUtil.getRep404Header());
            }
            //获取应用
            StandardContext context = host.mapperContext(request, response);
            if (context == null) {
                response.response(HttpProtocolUtil.getRep404Header());
            }
            //匹配Servlet，如果匹配不到，则返回DefaultHttpServlet(用于处理静态资源)
            StandardWrapper wrapper = context.mapperWrapper(request, response);
            //tomcat目录
            String homeDir = System.getProperty("catalina.home");
            if (StringUtils.isBlank(homeDir)) {
                homeDir=".";
            }
            //如果appBase以/开头代表是绝对路径，否则为相对路径
            String appDir=host.getAppBase().startsWith("/")?host.getAppBase()+File.separator+context.getDocBase():homeDir+File.separator+host.getAppBase()+File.separator+context.getDocBase();
            if (wrapper == null) {
                DefaultServlet defaultServlet = new DefaultServlet(appDir);
                defaultServlet.service(request, response);
            }else{
                //使用自定义类加载器加载Servlet类
                WebAppClassLoader classLoader = new WebAppClassLoader(appDir+File.separator+"WEB-INF" + File.separator + "classes");
                Class servletClass = classLoader.findClass(wrapper.getClassName());
                Servlet servlet = (Servlet)servletClass.newInstance();
                servlet.service(request, response);
            }

        }
    }

}
